use crate::page::Page;

#[derive(Debug)]
pub struct PageQueue {
    pub(crate) first: *mut Page,
    pub(crate) last: *mut Page,
    pub(crate) block_size: usize,
}

impl PageQueue {
    pub fn new(block_size: usize) -> Self {
        PageQueue {
            first: std::ptr::null_mut(),
            last: std::ptr::null_mut(),
            block_size,
        }
    }

    pub fn push_front(&mut self, page: *mut Page) {
        unsafe {
            (*page).next = self.first;
            (*page).prev = std::ptr::null_mut();

            if !self.first.is_null() {
                (*self.first).prev = page;
            } else {
                // If queue was empty, update last
                self.last = page;
            }

            self.first = page;
        }
    }

    pub fn push_back(&mut self, page: *mut Page) {
        unsafe {
            (*page).prev = self.last;
            (*page).next = std::ptr::null_mut();

            if !self.last.is_null() {
                (*self.last).next = page;
            } else {
                // If queue was empty, update first
                self.first = page;
            }

            self.last = page;
        }
    }

    pub fn remove(&mut self, page: *mut Page) {
        unsafe {
            if (*page).prev.is_null() {
                self.first = (*page).next;
            } else {
                (*(*page).prev).next = (*page).next;
            }

            if (*page).next.is_null() {
                self.last = (*page).prev;
            } else {
                (*(*page).next).prev = (*page).prev;
            }

            (*page).prev = std::ptr::null_mut();
            (*page).next = std::ptr::null_mut();
        }
    }

    pub fn is_empty(&self) -> bool {
        self.first.is_null()
    }

    pub fn peek_front(&self) -> Option<&mut Page> {
        if self.first.is_null() {
            None
        } else {
            unsafe { Some(&mut *self.first) }
        }
    }
}
